#include <event2/event.h>
#include <event2/listener.h>
#include <event2/http.h>
#include <event2/keyvalq_struct.h>
#include <event2/buffer.h>
#include <iostream>
#include <signal.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <string>

using namespace std;

static const char *ip = "0.0.0.0";
static const int port = 8080;
static const char *DEFAULTINDEX = "/index.html";

void http_cb(struct evhttp_request *req, void *arg) {
    cout << "http_cb" << endl;
    // 1. 获取浏览器请求信息
    // url < uri

    const char *uri = evhttp_request_get_uri(req);
    cout << uri << endl;

    string cmdtype;
    switch (evhttp_request_get_command(req)) {
    case EVHTTP_REQ_GET:
        cmdtype = "GET";
        break;
    case EVHTTP_REQ_POST:
        cmdtype = "POST";
        break;
    }
    cout << "cmdtype: " << cmdtype << endl;

    // 请求头
    evkeyvalq *headers = evhttp_request_get_input_headers(req);
    cout << "====== headers ======" << endl;
    for (evkeyval *p = headers->tqh_first; p != NULL; p = p->next.tqe_next) {
        cout << p->key << " : " << p->value << endl;
    }

    // 请求体
    evbuffer *req_body = evhttp_request_get_input_buffer(req);
    char data[1024] = {0};
    cout << "===== request body =====" << endl;
    while (evbuffer_get_length(req_body)) {
        int len = evbuffer_remove(req_body, data, sizeof(data) - 1);
        if (len > 0) {
            cout << data << endl;
        }
    }
    // 2. 回复请求

    // 设置根目录
    string filepath = ".";
    if (strcmp(uri, "/") == 0) {
        filepath += DEFAULTINDEX;
    } else {
        filepath += uri;
    }
    // 消息报头
    evkeyvalq *outheader = evhttp_request_get_output_headers(req);
    int pos = filepath.find(".", 1);
    string postfix = filepath.substr(pos + 1, filepath.size() - pos - 1);
    if (postfix == "jpg" || postfix == "gif" || postfix == "png") {
        string t = "image/" + postfix;
        evhttp_add_header(outheader, "Content-Type", t.c_str());
    } else if (postfix == "zip" || postfix == "rar") {
        evhttp_add_header(outheader, "Content-Type", "application/x-zip-compressed");
    } else if (postfix == "html") {
        // 手动添加 utf-8，不过不推荐；尽量写在前端
        // evhttp_add_header(outheader, "Content-Type", "text/html;charset=UTF8");
        evhttp_add_header(outheader, "Content-Type", "text/html");
    } else if (postfix == "css") {
        evhttp_add_header(outheader, "Content-Type", "text/css");
    }

    FILE *fp = fopen(filepath.c_str(), "rb");
    if (fp) {
        evbuffer *outbuf = evhttp_request_get_output_buffer(req);
        while (1) {
            int len = fread(data, 1, sizeof(data), fp);
            if (len <= 0) break;
            evbuffer_add(outbuf, data, len);
        }
        // evbuffer_add(outbuf, "<h1>It works!</h1>", 18);
        evhttp_send_reply(req, HTTP_OK, "reason", outbuf);
        fclose(fp);
        cout << "[ File Found ]" << endl;
    } else {
         evhttp_send_reply(req, HTTP_NOTFOUND, "reason", 0);
         cout << "replyed" << endl;
    }

    
}

int main() {
    // 忽略管道信号，避免发送数据给已关闭socket
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
        cout << "set pipe signal error" << endl;
        return 1;
    }
    // 创建 libevent 上下文
    event_base *base = event_base_new();
    if (base) {
        cout << "create new event base" << endl;
    }

    // http
    // 1. 创建 evhttp 上下文
    evhttp *evh = evhttp_new(base);

    // 2. 绑定端口和 IP
    if (evhttp_bind_socket(evh, ip, port) != 0) {
        cout << "bind failed" << endl;
    }

    // 3. 设定回调函数
    evhttp_set_gencb(evh, http_cb, 0);

    



    // 事件分发处理
    event_base_dispatch(base);
    // 释放资源
    assert(evh);
    evhttp_free(evh);
    assert(base);
    event_base_free(base);

}